#include	<stdio.h>
#include	<string.h>
#include	<stdlib.h>
#include	<stdbool.h>
#include	<unistd.h>
#include	<time.h>
#include	<netinet/in.h>
#include	<signal.h>
#include	<fcntl.h>
#include	<sys/ioctl.h>
#include	<sys/time.h>
#include	<event.h>
#include	<evutil.h>


#define MAX_PACKET_SIZE		8532
#define COORDINATOR_ID		1
#define MAX_GAP_LENGTH		10
#define STRING_SIZE			1024
#define CONFIG				"/home/parisa/Paxos-UDP/UDP-ring/config/l_config.txt"
#define STRING_SIZE				200000
#define N					5

struct timeval startTime,endTime, end, start,elapsedTime, performance_start_time, performance_end_time, throughput_elapsed_time, tv;
struct sockaddr_in ipmAddr;
struct event *timeout_ev, *socketEve, *socketEve2;
double throughput_vector[2000];
bool f=false,r_tag=false;
char fn[STRING_SIZE];

int PROCESS_ID, ipm_receiver_sid,senders, deliveryCount=0, nr=0, rd=0, redundant=0;
int lowestDelivered=-1, highestDeliverable=-1, nextDeliver=-1, throughput_counter=0, RECEIVED=0;
int LOST=0;
char result_file[STRING_SIZE];
#include "types.h"
inst *data[N];
result results[2000];
lost losts[2000];
int lost_counter=0;
inst *new_data;
int acceptor_sid;

#include "UDPconnections.h"
#include "TCPconnections.h"
#include "IpSource.h"
#include "learner.h"
#include "performance.h"
#include "initialize.h"


//------------------------------------------------------------------------------
void main_initialize();
//------------------------------------------------------------------------------
int main(int argc, char ** argv)
{	
	//---------------------Variables--------------------------------------------
	char ip[2][STRING_SIZE],port[2][STRING_SIZE],name[STRING_SIZE];
	main_initialize();
	if(argc!=3)
	  {
		  printf("Incompatibale call to this function. Try Again.!\n
				  1. First Parameter: PROCESS_ID.\n
				  2. folder to save the results.\n");
		  exit(1);
	  }
	PROCESS_ID=atoi(argv[1]);
	IP_PORT(CONFIG,PROCESS_ID,ip,port);
	event_init();
	
	strcpy(result_file,"/home/parisa/Paxos-UDP/UDP-ring/learner/result/experiment-9/");
	strcat(result_file,argv[2]);
	strcat(result_file,"/");
	strcat(result_file, argv[1]);
	strcat(result_file,".txt");
	
	
	strcpy(fn,"/home/parisa/learner-3/throughput/M");
	sprintf(name,"%d",PROCESS_ID);
	strcat(fn, name);
	strcat(fn,".dat");
	//ipmAddr=getAddr(atoi(port[0]), ip[0]);
	losts[lost_counter].count=0;
	//----------------------------------------------------------------------
	tv.tv_sec=1;
	tv.tv_usec=0;
	//=============================Acceptor=====================================	
	
	//close(acceptor_sid);
	//sleep(100);
	//=============================Multicaster==================================
	ipm_receiver_sid=create_ip_multicast_receiver_socket(atoi(port[0]),ip[0]);
	len_addr=sizeof(ipmAddr);
	//==========================================================================
	
	
	printf("ip:%s.",ip[1]);
	acceptor_sid = client_connection(atoi(port[1]),ip[1]);
	
	initialize();
	fprintf("-----------------------------------------------------------\n");
	gettimeofday(&start, NULL);
    gettimeofday(&startTime, NULL);
	gettimeofday(&performance_start_time,NULL);
	//-------Events-------------------------------------------------------------
	event_set(socketEve,ipm_receiver_sid,EV_READ|EV_PERSIST,recv_new_packet,NULL);
	status = event_add(socketEve,NULL);
	assert(status >= 0);
	//==========================================================================
	event_set(socketEve2,acceptor_sid,EV_READ|EV_PERSIST,recv_lost_packet,NULL);
	status = event_add(socketEve2,NULL);
	assert(status >= 0);
    //==========================================================================
	evtimer_set(timeout_ev, compute_performance, timeout_ev);
	status = evtimer_add(timeout_ev,&tv);
	assert(status >= 0);
    //==========================================================================
	event_dispatch();
	exit(0);
}
//------------------------------------------------------------------------------
void main_initialize()
{
	socketEve	=	(struct event*)malloc(sizeof(struct event));
	socketEve2	=	(struct event*)malloc(sizeof(struct event));
	timeout_ev	=	(struct event*)malloc(sizeof(struct event));
}
//------------------------------------------------------------------------------
